import Feature from "ol/Feature";
import { Geometry, Point, Circle } from "ol/geom";
import { containsCoordinate } from "ol/extent";
import Tooltip from "./Tooltip";
import { listen } from "ol/events";

import "./Popup.css";

function getTargetExtent(map, target) {
  if (
    Array.isArray(target) &&
    target.every(item => typeof item === "number") &&
    target.length === 4
  )
    return target;

  let geometry = null;

  if (target instanceof Feature) {
    geometry = target.getGeometry();
  } else if (target instanceof Geometry) {
    geometry = target;
  } else if (
    Array.isArray(target) &&
    target.every(item => typeof item === "number") &&
    target.length === 2
  ) {
    geometry = new Point(target);
  }

  if (geometry instanceof Point) {
    const coordinate = geometry.getCoordinates();
    const resolution = map.getView().getResolution();
    const extentSize = 5 * resolution;
    const extent = [
      coordinate[0] - extentSize,
      coordinate[1] - extentSize,
      coordinate[0] + extentSize,
      coordinate[1] + extentSize,
    ];

    return extent;
  } else {
    return geometry.getExtent();
  }
}

/**
 * Popup 弹出框覆盖物类，继承自 Tooltip。
 * @class
 * @augments Tooltip
 * @classdesc 自定义的 OpenLayers 弹出框覆盖物类，继承自 ol/Overlay。
 *
 * @param {Object} options 配置选项
 * @param {Feature | Geometry | import("ol/coordinate").Coordinate | import("ol/extent").Extent} options.target 所绑定的目标
 * @param {'click' | 'hover'} options.trigger 触发方式
 */
class Popup extends Tooltip {
  /**
   * 创建 Popup 实例。
   * @param {Object} options 配置选项
   * @param {Feature | Geometry | import("ol/coordinate").Coordinate | import("ol/extent").Extent} options.target 所绑定的目标
   * @param {'click' | 'hover'} options.trigger 触发方式
   */
  constructor(options) {
    super(options);

    /**
     * 是否已触发弹窗显示。
     * @type {boolean}
     * @private
     */
    this.isTrigger = false;

    /**
     * 弹窗的触发方式。
     * @type {'click' | 'hover'}
     * @private
     */
    this.trigger = options.trigger;

    /**
     * 所绑定的目标对象。
     * @type { Feature | Geometry | import("ol/coordinate").Coordinate | import("ol/extent").Extent}
     * @private
     */
    this.target = options.target;

    /**
     * 目标的范围。
     * @type { import("ol/extent").Extent}
     * @private
     */
    this.targetExtent = null;

    /**
     * 是否自动关闭弹窗
     * @type {boolean}
     * @private
     */
    this.isAutoClose =
      options.isAutoClose !== undefined ? options.isAutoClose : true;

    /**
     * 是否显示关闭按钮
     * @type {boolean}
     * @private
     */
    this.isShowCloseBtn =
      options.isShowCloseBtn !== undefined ? options.isShowCloseBtn : false;

    this.set("visibility", false);

    this.on("change:map", this.handlePopupMapChange);
  }

  /**
   * 处理地图变更时的回调。
   * @protected
   * @returns {void}
   */
  handlePopupMapChange() {
    const map = this.getMap();

    if (map) {
      this.targetExtent = getTargetExtent(map, this.target);

      const eventType = this.trigger === "click" ? "click" : "pointermove";
      this.listenKeys.push(
        listen(map, eventType, this.handleTargetTrigger, this)
      );
    } else {
      // 移除所有事件监听
      this.removeAllListeners();
    }
  }

  /**
   * 处理目标触发事件。
   * @protected
   * @param {import("ol/MapBrowserEvent").default} event 地图浏览事件对象
   * @returns {void}
   */
  handleTargetTrigger(event) {
    const coordinate = event.coordinate;
    if (containsCoordinate(this.targetExtent, coordinate)) {
      this.open();
    } else {
      this.isAutoClose && this.close();
    }
  }

  /**
   * 设置弹窗的可见性。
   * @override
   * @param {boolean} visibility 是否可见
   * @returns {void}
   */
  setVisibility(visibility) {
    if (!this.isTrigger && this.isOnZoomRange) return;
    this.set("visibility", visibility);
  }

  /**
   * 格式化弹窗元素。
   * @override
   * @param {HTMLElement} element 弹窗元素
   * @returns {HTMLElement} 格式化后的弹窗元素
   */
  formatElement(element) {
    const _element = super.formatElement(element);

    if (this.isUseContainer) {
      const container = _element;

      container.className = `ol-custom-popup ${this.getPlacement()}`;

      if (this.isShowCloseBtn) {
        const closeButton = document.createElement("div");
        closeButton.className = "ol-custom-popup-close";
        closeButton.innerHTML = "×";
        container.appendChild(closeButton);

        closeButton.addEventListener(
          "click",
          function () {
            this.close();
          }.bind(this)
        );
      }
    }

    return _element;
  }

  /**
   * 关闭弹窗。
   * @returns {void}
   */
  close() {
    this.isTrigger = false;
    this.set("visibility", false);
  }

  /**
   * 打开弹窗。
   * @returns {void}
   */
  open() {
    this.isTrigger = true;
    this.set("visibility", true);
  }
}

export default Popup;
